/*
 * File: User.java Author: Robert Bittle <guywithnose@gmail.com>
 */
package faceBook;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.sql.Date;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONString;
import data.JavaCurl;
import foxtrotbravo.Config;
import foxtrotbravo.DataConnection;
import foxtrotbravo.DataObject;

/**
 * The Class User.
 */
public class User implements DataObject, JSONString
{

  /** The ID. */
  private long ID;

  /** The email. */
  private String email;

  /** The access token. */
  private String accessToken;

  /** The expire time. */
  private Date expireTime;

  /** The birthday. */
  private Date birthday;

  /** The friends. */
  private ArrayList<User> friends = null;

  /** The reply message. */
  private String replyMessage;

  /** The reply message. */
  private String defaultBDMessageMale;

  /** The reply message. */
  private String defaultBDMessageFemale;

  /** The reply message. */
  private Boolean useReply = false;

  /** The reply message. */
  private Boolean useDefaultBD = false;

  /** The gender. */
  private String gender;

  /** The first name. */
  private String firstName;

  /** The last name. */
  private String lastName;

  /** The is fan. */
  private boolean isFan;

  /**
   * Instantiates a new user.
   */
  private User()
  {
  }

  /**
   * Instantiates a new user.
   * 
   * @param id
   *          the id
   */
  public User(long id)
  {
    ID = id;
    load();
  }

  /**
   * Gets the email.
   * 
   * @return the email
   */
  public String getEmail()
  {
    return email;
  }

  /**
   * Sets the email.
   * 
   * @param Email
   *          the new email
   */
  public void setEmail(String Email)
  {
    email = Email;
  }

  /**
   * Get Reply message.
   * 
   * @return the reply message
   */
  public String getReplyMessage()
  {
    return replyMessage;
  }

  /**
   * Sets the reply message.
   * 
   * @param ReplyMessage
   *          the new reply message
   */
  public void setReplyMessage(String ReplyMessage)
  {
    replyMessage = ReplyMessage;
  }

  /**
   * Gets the access token.
   * 
   * @return the access token
   */
  public String getAccessToken()
  {
    return accessToken;
  }

  /**
   * Sets the access token.
   * 
   * @param AccessToken
   *          the new access token
   */
  public void setAccessToken(String AccessToken)
  {
    accessToken = AccessToken;
  }

  /**
   * Gets the expire time.
   * 
   * @return the expire time
   */
  public Date getExpireTime()
  {
    return expireTime;
  }

  /**
   * Sets the expire time.
   * 
   * @param ExpireTime
   *          the new expire time
   */
  public void setExpireTime(Date ExpireTime)
  {
    expireTime = ExpireTime;
  }

  /**
   * Sets the expire time.
   * 
   * @param ExpireTime
   *          the new expire time
   */
  public void setExpireTime(long ExpireTime)
  {
    expireTime = new Date(ExpireTime);
  }

  /**
   * Gets the birthday.
   * 
   * @return the birthday
   */
  public Date getBirthday()
  {
    return birthday;
  }

  /**
   * Sets the birthday.
   * 
   * @param Birthday
   *          the new birthday
   */
  public void setBirthday(Date Birthday)
  {
    birthday = Birthday;
  }

  /**
   * Sets the birthday.
   * 
   * @param Birthday
   *          the new birthday
   */
  public void setBirthday(long Birthday)
  {
    birthday = new Date(Birthday);
  }

  /**
   * Gets the iD.
   * 
   * @return the iD
   */
  public long getID()
  {
    return ID;
  }

  /**
   * Get Default bd message male.
   * 
   * @return the default bd message male
   */
  public String getDefaultBDMessageMale()
  {
    return defaultBDMessageMale;
  }

  /**
   * Sets the default bd message male.
   * 
   * @param DefaultBDMessageMale
   *          the new default bd message male
   */
  public void setDefaultBDMessageMale(String DefaultBDMessageMale)
  {
    defaultBDMessageMale = DefaultBDMessageMale;
  }

  /**
   * Get Default bd message female.
   * 
   * @return the default bd message female
   */
  public String getDefaultBDMessageFemale()
  {
    return defaultBDMessageFemale;
  }

  /**
   * Sets the default bd message female.
   * 
   * @param DefaultBDMessageFemale
   *          the new default bd message female
   */
  public void setDefaultBDMessageFemale(String DefaultBDMessageFemale)
  {
    defaultBDMessageFemale = DefaultBDMessageFemale;
  }

  /**
   * Get Use reply.
   * 
   * @return the use reply
   */
  public Boolean getUseReply()
  {
    return useReply;
  }

  /**
   * Sets the use reply.
   * 
   * @param UseReply
   *          the new use reply
   */
  public void setUseReply(Boolean UseReply)
  {
    useReply = UseReply;
  }

  /**
   * Get Use default bd.
   * 
   * @return the use default bd
   */
  public Boolean getUseDefaultBD()
  {
    return useDefaultBD;
  }

  /**
   * Sets the use default bd.
   * 
   * @param UseDefaultBD
   *          the new use default bd
   */
  public void setUseDefaultBD(Boolean UseDefaultBD)
  {
    useDefaultBD = UseDefaultBD;
  }

  /**
   * Get Gender.
   * 
   * @return the gender
   */
  public String getGender()
  {
    return gender;
  }

  /**
   * Sets the gender.
   * 
   * @param Gender
   *          the new gender
   */
  public void setGender(String Gender)
  {
    gender = Gender.substring(0, 1).toUpperCase();
  }

  /**
   * Get First name.
   * 
   * @return the first name
   */
  public String getFirstName()
  {
    return firstName;
  }

  /**
   * Sets the first name.
   * 
   * @param FirstName
   *          the new first name
   */
  public void setFirstName(String FirstName)
  {
    firstName = FirstName;
  }

  /**
   * Get Last name.
   * 
   * @return the last name
   */
  public String getLastName()
  {
    return lastName;
  }

  /**
   * Sets the last name.
   * 
   * @param LastName
   *          the new last name
   */
  public void setLastName(String LastName)
  {
    lastName = LastName;
  }

  /**
   * Checks if is fan.
   * 
   * @return true, if is fan
   */
  public boolean isFan()
  {
    return isFan;
  }

  /**
   * Sets the fan.
   * 
   * @param IsFan
   *          the new fan
   */
  public void setFan(boolean IsFan)
  {
    isFan = IsFan;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.json.JSONString#toJSONString()
   */
  @Override
  public String toJSONString()
  {
    return toJSONObject().toString();
  }

  /**
   * To json object.
   * 
   * @return the jSON object
   */
  public JSONObject toJSONObject()
  {
    JSONObject JO = new JSONObject();
    try
    {
      JO.put("id", ID);
      JO.put("email", email);
      JO.put("accessToken", accessToken);
      JO.put("expireTime", expireTime);
      JO.put("birthday", birthday);
      JO.put("replyMessage", replyMessage);
      JO.put("defaultBDMessageMale", defaultBDMessageMale);
      JO.put("defaultBDMessageFemale", defaultBDMessageFemale);
      JO.put("useDefaultDB", useDefaultBD);
      JO.put("useReply", useReply);
      JO.put("gender", gender);
      JO.put("firstName", firstName);
      JO.put("lastName", lastName);
    } catch (JSONException e)
    {
      // Do Nothing
    }
    return JO;
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString()
  {
    return toJSONString();
  }

  /*
   * (non-Javadoc)
   * 
   * @see foxtrotbravo.DataObject#save()
   */
  @Override
  public boolean save()
  {
    try
    {
      if (exists())
      {
        return update();
      }
      return insert();
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return false;
  }

  /**
   * Exists.
   * 
   * @return true, if object exists
   */
  public boolean exists()
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select 1 from user where id = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, ID);
        ResultSet results = stmt.executeQuery();
        return results.next();
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return false;
  }

  /*
   * (non-Javadoc)
   * 
   * @see foxtrotbravo.DataObject#load()
   */
  @Override
  public boolean load()
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select email, accessToken, expireTime, birthday, reply, defaultBDMessageMale, defaultBDMessageFemale, useDefaultBD, useReply, gender, firstName, lastName, isFan from user where id = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, ID);
        ResultSet results = stmt.executeQuery();
        if (results.next())
        {
          email = results.getString("email");
          accessToken = results.getString("accessToken");
          expireTime = results.getDate("expireTime");
          birthday = results.getDate("birthday");
          replyMessage = results.getString("reply");
          defaultBDMessageMale = results.getString("defaultBDMessageMale");
          defaultBDMessageFemale = results.getString("defaultBDMessageFemale");
          useDefaultBD = results.getBoolean("useDefaultBD");
          useReply = results.getBoolean("useReply");
          gender = results.getString("gender");
          firstName = results.getString("firstName");
          lastName = results.getString("lastName");
          isFan = results.getBoolean("isFan");
          return true;
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return false;
  }

  /**
   * Gets the friends.
   * 
   * @return the friends
   */
  public ArrayList<User> getFriends()
  {
    if (friends == null)
    {
      friends = new ArrayList<User>();
      try
      {
        if (DataConnection.connect())
        {
          String statement = "select id, email, accessToken, expireTime, birthday, reply, defaultBDMessageMale, defaultBDMessageFemale, useDefaultBD, useReply, gender, firstName, lastName, isFan from user where id in (select friend from friends where user = ?)";
          PreparedStatement stmt = DataConnection.getConnection()
              .prepareStatement(statement);
          stmt.setLong(1, ID);
          ResultSet results = stmt.executeQuery();
          while (results.next())
          {
            User friend = new User();
            friend.ID = results.getLong("id");
            friend.email = results.getString("email");
            friend.accessToken = results.getString("accessToken");
            friend.expireTime = results.getDate("expireTime");
            friend.birthday = results.getDate("birthday");
            friend.replyMessage = results.getString("reply");
            defaultBDMessageMale = results.getString("defaultBDMessageMale");
            defaultBDMessageFemale = results
                .getString("defaultBDMessageFemale");
            friend.useDefaultBD = results.getBoolean("useDefaultBD");
            friend.useReply = results.getBoolean("useReply");
            friend.gender = results.getString("gender");
            friend.firstName = results.getString("firstName");
            friend.lastName = results.getString("lastName");
            friend.isFan = results.getBoolean("isFan");
            friends.add(friend);
          }
        }
      } catch (SQLException e)
      {
        e.printStackTrace();
      }
    }
    return friends;
  }

  /**
   * Adds the friend.
   * 
   * @param friend
   *          the friend
   */
  public void addFriend(User friend)
  {
    getFriends();
    friends.add(friend);
    friend.save();
    if (DataConnection.connect())
    {
      try
      {
        String statement = "INSERT INTO friends (user, friend) VALUES ( ?, ? )";
        PreparedStatement stmt;
        stmt = DataConnection.getConnection().prepareStatement(statement);
        stmt.setLong(1, getID());
        stmt.setLong(2, friend.getID());
        stmt.executeUpdate();
      } catch (SQLException e)
      {
        // Do Nothing
      }
    }
  }

  /**
   * Removes the friend.
   * 
   * @param friend
   *          the friend
   */
  public void removeFriend(User friend)
  {
    friends.remove(friend);
    if (DataConnection.connect())
    {
      try
      {
        String statement = "delete from friends where user = ? and friend = ? ";
        PreparedStatement stmt;
        stmt = DataConnection.getConnection().prepareStatement(statement);
        stmt.setLong(1, getID());
        stmt.setLong(2, friend.getID());
        stmt.executeUpdate();
      } catch (SQLException e)
      {
        e.printStackTrace();
      }
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see foxtrotbravo.DataObject#delete()
   */
  @Override
  public boolean delete()
  {
    try
    {
      if (DataConnection.connect())
      {
        String statement = "delete from user where id = ?";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        stmt.setLong(1, ID);
        int success = 2;
        success = stmt.executeUpdate();
        return success == 1;
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return true;
  }

  /**
   * Update.
   * 
   * @return true, if successful
   * @throws SQLException
   *           the SQL exception
   */
  private boolean update() throws SQLException
  {
    if (DataConnection.connect())
    {
      String statement = "update user set email = ?, accessToken = ?, expireTime = ?, birthday = ?, reply = ?, defaultBDMessageMale = ?, defaultBDMessageFemale = ?, useDefaultBD = ?, useReply = ?, gender = ?, firstName = ?, lastName = ?, isFan = ? where id = ?";
      PreparedStatement stmt = DataConnection.getConnection().prepareStatement(
          statement);
      stmt.setString(1, email);
      stmt.setString(2, accessToken);
      stmt.setDate(3, expireTime);
      stmt.setDate(4, birthday);
      stmt.setString(5, replyMessage);
      stmt.setString(6, defaultBDMessageMale);
      stmt.setString(7, defaultBDMessageFemale);
      stmt.setBoolean(8, useDefaultBD);
      stmt.setBoolean(9, useReply);
      stmt.setString(10, gender);
      stmt.setString(11, firstName);
      stmt.setString(12, lastName);
      stmt.setBoolean(13, isFan);
      stmt.setLong(14, ID);
      int success = 2;
      success = stmt.executeUpdate();
      return success == 1;
    }
    return false;
  }

  /**
   * Insert.
   * 
   * @return true, if successful
   * @throws SQLException
   *           the sQL exception
   */
  private boolean insert() throws SQLException
  {
    if (DataConnection.connect())
    {
      String statement = "INSERT INTO user (id, email, accessToken, expireTime, birthday, reply, defaultBDMessageMale, defaultBDMessageFemale, useDefaultBD, useReply, gender, firstName, lastName, isFan) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )";
      PreparedStatement stmt = DataConnection.getConnection().prepareStatement(
          statement, Statement.RETURN_GENERATED_KEYS);
      stmt.setLong(1, ID);
      stmt.setString(2, email);
      stmt.setString(3, accessToken);
      stmt.setDate(4, expireTime);
      stmt.setDate(5, birthday);
      stmt.setString(6, replyMessage);
      stmt.setString(7, defaultBDMessageMale);
      stmt.setString(8, defaultBDMessageFemale);
      stmt.setBoolean(9, useDefaultBD);
      stmt.setBoolean(10, useReply);
      stmt.setString(11, gender);
      stmt.setString(12, firstName);
      stmt.setString(13, lastName);
      stmt.setBoolean(14, isFan);
      int success = 2;
      success = stmt.executeUpdate();
      ResultSet key = stmt.getGeneratedKeys();
      if (key.next())
      {
        ID = key.getLong(1);
      }
      return success == 1;
    }
    return false;
  }

  /**
   * Get All active users access tokens.
   * 
   * @return the all active users access tokens
   */
  public static ArrayList<User> getAllActiveUsers()
  {
    ArrayList<User> users = new ArrayList<User>();
    try
    {
      if (DataConnection.connect())
      {
        String statement = "select id from user where accessToken is not null";
        PreparedStatement stmt = DataConnection.getConnection()
            .prepareStatement(statement);
        ResultSet results = stmt.executeQuery();
        while (results.next())
        {
          users.add(new User(Long.valueOf(results.getString("id"))));
        }
      }
    } catch (SQLException e)
    {
      e.printStackTrace();
    }
    return users;
  }

  /**
   * Checks for permissions.
   * 
   * @return true, if successful
   */
  public boolean hasPostPermissions()
  {
    String response = JavaCurl
        .getUrl("https://graph.facebook.com/me/permissions?access_token="
            + accessToken);
    boolean hasPermissions = true;
    try
    {
      JSONObject jo = new JSONObject(response).getJSONArray("data")
          .getJSONObject(0);
      String[] requiredPermissions = new String[]
      {
          "email", "publish_stream", "user_birthday", "friends_birthday"
      };
      for (int i = 0; i < requiredPermissions.length; i++)
      {
        if (!jo.has(requiredPermissions[i])
            || jo.getInt(requiredPermissions[i]) != 1)
          hasPermissions = false;
      }
    } catch (JSONException e)
    {
      hasPermissions = false;
      e.printStackTrace();
    }
    return hasPermissions;
  }

  /**
   * Replace string.
   * 
   * @param message
   *          the message
   * @return the string
   */
  public String replaceString(String message)
  {
    if (firstName == null)
      firstName = "";
    if (lastName == null)
      lastName = "";
    return message.replaceAll("\\*FIRST_NAME\\*", firstName).replaceAll(
        "\\*LAST_NAME\\*", lastName);
  }

  /**
   * Get Custom message count.
   * 
   * @return the custom message count
   */
  public int getCustomMessageCount()
  {
    String response = JavaCurl
        .getUrl("https://api.facebook.com/restserver.php?access_token="
            + accessToken + "&api_key=" + Config.AppId
            + "&format=json-strings&method=pages.isFan&page_id="
            + Config.PageId);
    int freeMessages = 2;
    // 3 free message for liking us
    if ("true".equals(response.trim()))
    {
      freeMessages += 3;
    }
    int messagesUsed = Message.getUserCustomMessageCount(this);
    return Purchase.getMessageCountForUser(this) + freeMessages - messagesUsed;
  }

}
